#!/usr/bin/env python
# -*- python -*-

# Copyright (c) 2007, SUZUKI Tetsuya <suzuki@spice-of-life.net>.
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# $Id: lineguide 125 2009-08-17 15:12:12Z tetsuya.suzuki $

import sys
import os.path
import optparse
import re
import string
import cStringIO
import StringIO
import inspect

VERSION_NUMBER = '0.6'
USAGE          = '%prog [options] [file...]'
VERSION        = 'lineguide %s' % VERSION_NUMBER

HELP_TAB_BASE       = 4

frame = inspect.currentframe()

def line_control(lineno):
    return (lineno + 1, __file__)


#
# parsing command line options
#

class Option(object):
    
    def __init__(self, sopt=None, lopt=None, args=(), vargs=False,
                 path=None, action=None, **kws):
        self.path = path or __file__
        self.sopt = sopt
        self.lopt = lopt
        self.args = args
        self.nargs = len(args)
        if vargs:
            self.nargs -= 1
        self.has_vargs = vargs
        self.action = action
        self.attrs = {}
        self.set_attrs(kws)

    def base_sopt(self):
        return self.sopt.strip('-')
    
    def base_lopt(self):
        return self.lopt.strip('-')

    def set_attrs(self, d):
        for key, value in d.items():
            if not isinstance(value, list):
                value = [value]
            self.set_attr(key, value)

    def set_attr(self, name, values):
        ps = []
        ts = []
        for value in values:
            if isinstance(value, ConfigToken):
                ps.append(value.py_value())
                ts.append(value)
            else:
                ps.append(value)
        attr = OPTION_ATTRS[name](*ps)
        attr.tokens = ts
        attr.init_option(self)

    def help_name(self):
        name = ''
        if self.sopt:
            name = self.sopt
            if self.args:
                name += ' ' + ' '.join(self.args)
                if self.has_vargs:
                    name += ' ...'
        if self.lopt:
            if self.sopt:
                name += ', %s' % self.lopt
            else:
                name = self.lopt
            if self.args:
                name += ' ' + ' '.join(self.args)
                if self.has_vargs:
                    name += ' ...'
        return name

    def validate(self, confp):
        for name, attr in self.attrs.items():
            attr.validate_unit(confp, self)
            attr.init_option(self)
        for name, attr in self.attrs.items():
            attr.validate_depend(confp, self)
            attr.init_option(self)

    def c_default_values(self):
        t = self.arg_type
        values = []
        for value in self.default_values:
            if value is None:
                if t == STR_ARG_TYPE:
                    value = 'NULL'
                elif t in (INT_ARG_TYPE, UINT_ARG_TYPE, FLOAT_ARG_TYPE):
                    value = '0'
                else:
                    raise ValueError, 'unknown type -- %d' % t
            else:
                if t == STR_ARG_TYPE:
                    value = cstring(value)
                elif t in (INT_ARG_TYPE, UINT_ARG_TYPE, FLOAT_ARG_TYPE):
                    value = str(value)
                else:
                    raise ValueError, 'unknown type -- %d' % t
            values.append(value)
        return values

    def c_format_action(self, args):
        ARG_RE = re.compile(r'\A\$(\w+)')
        sc = StringScanner(self.action.code)
        code = StringIO.StringIO()
        mem = C_ARG_MEMBER[self.arg_type]
        while not sc.eos():
            arg = sc.scan(ARG_RE)
            if arg:
                name = arg[1:]
                if name == 'nvargs':
                    s = '%s->nvargs' % args
                else:
                    ref = sc.scan_block(LBRACKET_RE, RBRACKET_RE)
                    if ref:
                        s = '%s->vargs[%s].%s' % (args, ref, mem)
                    else:
                        i = self.args.index(name)
                        s = '%s->args[%d].%s' % (args, i, mem)
                code.write(s)
            else:
                code.write(sc.getc())
        return code.getvalue()


class OptionParser(object):

    program = ''
    version = 'Eternal Beta'
    usage = '[options] args...'
    output = None

    def __init__(self):
        self.options = []
        self.pos = Option()
        self.minus1 = Option() # "-" option
        self._init_version_option()
        self._init_help_option()
        self.c_decls = []
        self.add_codes = []

    def _init_version_option(self):
        lineno = inspect.getsourcelines(self._init_version_option)[1]+3
        code = CodeBlock(lineno,
                         '%sprint_version_and_exit(0);' % options.sym_prefix)
        self.add_option('-V', '--version',
                        help='Print version and exit',
                        action=code)

    def _init_help_option(self):
        lineno = inspect.getsourcelines(self._init_help_option)[1]+3
        code = CodeBlock(lineno,
                         '%sprint_help_and_exit(0);' % options.sym_prefix)
        self.add_option('-h', '--help',
                        help='Print this message',
                        action=code)

    def all_options(self):
        return self.options + [self.pos, self.minus1]
    
    def add_option(self, sopt, lopt=None, args=(), vargs=False,
                   path=None, action=None, **kws):
        opt = Option(sopt, lopt, args, vargs, path, action, **kws)
        self.options.append(opt)
        opt.index = self.options.index(opt)
        self._update_options()
        return opt
        
    def _update_options(self):
        self.pos.index = len(self.options)
        self.minus1.index = len(self.options) + 1
        
    def set_pos(self, args=(), vargs=False, path=None, action=None, **kws):
        self.pos = Option(None, None, args, vargs, path, action, **kws)
        self._update_options()
        return self.pos
        
    def set_minus1(self, path=None, action=None, **kws):
        self.minus1 = Option(None, None, (), False, path, action, **kws)
        self._update_options()
        return self.minus1
        
    def add_code(self, path, lineno, code):
        print_debug("%s:%d: additional C code" % (path, lineno))
        self.add_codes.append([lineno, path, code])

    def format(self, s):
        s = re.sub('%program', self.program, s)
        return s

    def format_usage(self):
        return self.format(self.usage)
    
    def format_version(self):
        return self.format(self.version)
    
    def option_helps(self):
        SPLIT_SIZE = 27
        names = []
        msgs = []
        for opt in self.options:
            names.append(opt.help_name())
            msgs.append(opt.help)

        maxlen = 0
        for name in names:
            if len(name) < SPLIT_SIZE:
                maxlen = max(len(name), maxlen)
        width = (maxlen / HELP_TAB_BASE + 2) * HELP_TAB_BASE
        helps = []
        for i, name in enumerate(names):
            msg = msgs[i]
            if len(name) >= SPLIT_SIZE:
                helps.append(name)
                helps.append(' ' * width + msg)
            else:
                helps.append(name.ljust(width) + msgs[i])
        return helps

    def max_noptargs(self):
        return max([opt.nargs for opt in self.options])


#
# generating C code
#

class CGenerator(file):

    LN          = '\n'
    VAR_MACRO    = 'VAR'
    CMD_VAR     = 'cmd'
    PARSE_FUNC  = 'parse'
    indent_size = 2

    def __init__(self, parser, path):
        file.__init__(self, path, 'w')
        self.parser = parser
        self.path = path
        self.indent_lv = 0
        self.prefix = options.sym_prefix
        self.const_prefix = self.prefix.upper()
        self.var_macro = self.const_prefix + self.VAR_MACRO
        self.cmd_var = self.prefix + self.CMD_VAR
        self.parse_func = self.prefix + self.PARSE_FUNC
        
    def indent(self):
        self.indent_lv += 1

    def dedent(self):
        self.indent_lv -= 1

    def write_i(self, s=None):
        self.write(self.indent_lv * self.indent_size * ' ')
        if s:
            self.write(s)

    def write_iln(self, s=None, count=1):
        self.write_i()
        self.write_ln(s, count)

    def write_ln(self, s=None, count=1):
        if s:
            self.write(s)
        self.write(self.LN * count)

    def write_template(self, s, sdict=None):
        t = string.Template(s)
        self.write(t.substitute(sdict or self.template))
        
    def write_line(self, line, path=None, code=None, sdict=None):
        if options.lines:
            if not path:
                path = self.path
            self.write_ln('#line %d "%s"' % (line, path))
        if code:
            self.write_template(code, sdict)

    def write_include(self, path):
        self.write_ln('#include "%s"' % path)
        
    def write_include_sys(self, path):
        self.write_ln('#include <%s>' % path)

    def write_ifdef(self, s):
        self.write_ln('#ifdef %s' % s)
    
    def write_endif(self, s=None):
        if s:
            self.write_ln('#endif /* %s */' % s)
        else:
            self.write_ln('#endif')
    
    def write_header(self):
        self.write_line(*C_HEADER_LINE)
        self.write_template(C_HEADER)

    def write_footer(self):
        self.write_line(*C_FOOTER_LINE)
        self.write_template(C_FOOTER)

    def write_begin_cpp(self):
        self.write_ifdef('__cplusplus')
        self.write_ln('extern "C" {')
        self.write_ifdef('0')
        self.write_ln('} /* for editor */')
        self.write_endif()
        self.write_endif('__cplusplus')
        self.write_ln()

    def write_end_cpp(self):
        self.write_ifdef('__cplusplus')
        self.write_ln('}')
        self.write_endif('__cplusplus')

    def generate(self):
        print_verbose('generate C source file -- %s' % self.path)
        self.init_template()
        self.write_header()        
        self.generate_template_decl()
        self.generate_c_decls()
        self.generate_template_funcs()
        self.generate_add_codes()
        self.write_footer()
        self.close()

    def init_template(self):        
        self.template = {'path':self.path,
                         'prefix':self.prefix,
                         'PREFIX':self.const_prefix,
                         'var_macro':self.var_macro,
                         'cmd':self.cmd_var,
                         'usage':self.parser.format_usage(),
                         'version':self.parser.format_version(),
                         'nopts':len(self.parser.options) or 1,
                         'max_noptargs':self.parser.max_noptargs() or 1}
        self.generate_decls()
        self.generate_set_const_func()
        self.generate_validate_selects_func()

    def decl_var(self, var):
        return '%s(%s)' % (self.var_macro, var)
    
    def generate_decls(self):
        self.generate_decl_tags()
        self.generate_decl_helps()
        self.generate_decl_action_decls()
        self.generate_decl_opt_infos()
        self.generate_init_defvals()
    
    def generate_decl_tags(self):
        tags = []
        for opt in self.parser.options:
            opt.c_token_tag = '%sOPT%d_TAG' % (self.const_prefix, opt.index)
            tags.append(opt.c_token_tag)
        tagdecl = ''
        for t in tags:
            tagdecl += '  %s,\n' % t
        self.template['tags'] = tagdecl

    def generate_decl_helps(self):
        helps = '    "' + \
                '",\n    "'.join(self.parser.option_helps()) + \
                '",\n'
        self.template['helps'] = helps

    def generate_decl_action_decls(self):
        actions = []
        for opt in self.parser.all_options():
            if opt.action:
                opt.c_action_name = '%sopt%d_action' % (self.prefix, opt.index)
                decl = 'static void %s(%sarg_list *);\n' % \
                       (opt.c_action_name, self.prefix)
                actions.append(decl)
        self.template['actions'] = ''.join(actions)

    def generate_decl_opt_infos(self):
        opt_infos = []
        for opt in self.parser.options:
            opt_infos.append(self.generate_opt_info(opt))
        opt_infos.append(self.generate_opt_info(self.parser.pos))
        opt_infos.append(self.generate_opt_info(self.parser.minus1))
        self.template['opt_infos'] = '\n'.join(opt_infos)

    def generate_opt_info(self, opt):
        info = [str(opt.index)]

        # short option
        if opt.sopt:
            info.append("'%s'" % opt.base_sopt())
        else:
            info.append('0')

        # long option
        if opt.lopt:
            info.append('"%s"' % opt.base_lopt())
        else:
            info.append('0')

        # deprecation message
        if opt.deprecate:
            info.append('"%s"' % opt.deprecate)
        else:
            info.append('0')

        # number of arguments
        info.append(str(opt.nargs))

        # number of default values
        info.append(str(len(opt.default_values)))

        # variable arguments
        info.append(str(int(opt.has_vargs)))
        
        # argument type
        info.append(str(opt.arg_type))

        # whether once or multiple option
        info.append(str(int(not opt.once)))
        
        # action
        if opt.action:
            info.append('(%saction_func)%s' % (self.prefix, opt.c_action_name))
        else:
            info.append('0')
        return '  {%s},' % ', '.join(info)

    def generate_init_defvals(self):
        inits = []
        base = '%sdefault_values' % self.prefix
        for opt in self.parser.options:
            for i, value in enumerate(opt.c_default_values()):
                t = opt.arg_type
                try:
                    mem = C_DEFVAL_MEMBER[t]
                except KeyError:
                    raise ValueError, 'unknown type -- %d' % t
                s = '  %s[%d][%d].%s = %s;\n' % \
                    (base, opt.index, i, mem, value)
                inits.append(s)
        self.template['init_defvals'] = ''.join(inits)

    def generate_set_const_func(self):
        s = StringIO.StringIO()
        first1 = True
        for opt in self.parser.options:
            if not opt.consts:
                continue
            first2 = True
            s.write('  ')
            if first1:
                first1 = False
            else:
                s.write('else ')
            s.write('if (tag == %s) {\n' % opt.c_token_tag)

            for name, value in opt.consts.items():
                s.write('    ')
                if first2:
                    first2 = False
                else:
                    s.write('else ')
                s.write('if (strcmp(%s, name) == 0) {\n' % cstring(name))
                s.write('      arg->%s = %s;\n' % \
                        (C_DEFVAL_MEMBER[opt.arg_type],
                         crepr(opt.arg_type, value)))
                s.write('      return 1;\n    }\n')
            
            s.write('  }\n')
        self.template['set_const'] = s.getvalue()

    def generate_validate_selects_func(self):
        s = StringIO.StringIO()
        first = True
        for opt in self.parser.options:
            if not opt.selects:
                continue
            first2 = True
            s.write('  ')
            if first:
                first = False
            else:
                s.write('else ')
            s.write('if (tag == %s) {\n' % opt.c_token_tag)
            s.write('    if (')
            for i, value in enumerate(opt.selects):
                if i > 0:
                    s.write('  && ')
                if opt.arg_type == STR_ARG_TYPE:
                    s.write('strcmp(%s, arg->sval) != 0' % cstring(value))
                else:
                    s.write('arg->%s != ' % \
                        (C_DEFVAL_MEMBER[opt.arg_type],
                         crepr(opt.arg_type, value)))
            s.write(')\n')
            s.write('    %sraise(LG_SELECT_ERROR, tag, NULL, 0);\n' % self.prefix)
            s.write('  }\n')
        self.template['validate_selects'] = s.getvalue()

    def generate_template_decl(self):
        self.write_line(*C_DECL_LINE)
        self.write_template(C_DECL)
        
    def generate_c_decls(self):
        for line, path, code in self.parser.c_decls:
            self.write_line(line, path, code)

    def generate_template_funcs(self):
        self.write_line(*C_FUNCS_LINE)
        self.write_template(C_FUNCS)
        self.generate_option_actions()

    def generate_option_actions(self):
        for opt in self.parser.all_options():
            if opt.action:
                name = '__list'
                decl = self.decl_var('%sarg_list *%s' % (self.prefix, name))
                code = opt.c_format_action(name)
                f = 'static void\n%s(%s)\n{%s}\n\n' % \
                    (opt.c_action_name, decl, code)
                self.write_line(opt.action.lineno-2, opt.path, f)
    
    def generate_add_codes(self):
        self.write_add_code_print_usage_and_exit()
        self.write_add_code_print_version_and_exit()
        self.write_add_code_print_help_and_exit()
        for line, path, code in self.parser.add_codes:
            self.write_line(line, path, code)
        
    def write_add_code_print_usage_and_exit(self):
        self.write_line(*C_PRINT_USAGE_AND_EXIT_LINE)
        self.write_template(C_PRINT_USAGE_AND_EXIT)

    def write_add_code_print_version_and_exit(self):
        self.write_line(*C_PRINT_VERSION_AND_EXIT_LINE)
        self.write_template(C_PRINT_VERSION_AND_EXIT)

    def write_add_code_print_help_and_exit(self):
        self.write_line(*C_PRINT_HELP_AND_EXIT_LINE)
        self.write_template(C_PRINT_HELP_AND_EXIT)

C_HEADER_LINE = line_control(frame.f_lineno)
C_HEADER = '''/* $path is generated by lineguide. Do not edit! */

'''

C_FOOTER_LINE = line_control(frame.f_lineno)
C_FOOTER = '''
/* End of $path */
'''

C_DECL_LINE = line_control(frame.f_lineno)
C_DECL = '''#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>

#ifdef __GNUC__
#define ${var_macro}(v)   v __attribute__((unused))
#else
#define ${var_macro}(v)   v
#endif

typedef struct _${prefix}opt_info     ${prefix}opt_info;
typedef struct _${prefix}arg_list     ${prefix}arg_list;
typedef union _${prefix}arg           ${prefix}arg;
typedef struct _${prefix}token        ${prefix}token;
typedef struct _${prefix}error_info   ${prefix}error_info;

typedef void (*${prefix}action_func)(${prefix}arg_list *);

enum ${PREFIX}TAG {
${tags}
  ${PREFIX}POS_ARGS_TAG,
  ${PREFIX}MINUS1_TAG,
  ${PREFIX}ASSOC_ARG_TAG,
  ${PREFIX}ARG_TAG
};

#define ${PREFIX}OPT_COUNT    ${PREFIX}MINUS1_TAG

enum ${PREFIX}ARG_TYPE {
  ${PREFIX}STR_TYPE,
  ${PREFIX}INT_TYPE,
  ${PREFIX}UINT_TYPE,
  ${PREFIX}FLOAT_TYPE
};

enum ${PREFIX}ERROR_CODE {
  ${PREFIX}RANGE_ERROR,
  ${PREFIX}CONVERT_ERROR,
  ${PREFIX}MULTIPLE_ERROR,
  ${PREFIX}SELECT_ERROR,
  ${PREFIX}USER_ERROR
};

struct _${prefix}opt_info {
  int tag;
  const char sopt;
  const char *lopt;
  const char *dep;
  int nargs;
  int ndefvals;
  int var_args;
  int arg_type;
  int multiple;
  ${prefix}action_func action;
};

struct _${prefix}arg_list {
  int arg_type;
  int nargs;
  int nvargs;
  union _${prefix}arg *args;
  union _${prefix}arg *vargs;
};

union _${prefix}arg {
  const char *csval;
  char *sval;
  long lval;
  unsigned long ulval;
  double dval;
};

struct _${prefix}token {
  int tag;
  char *value;
  struct _${prefix}token *next;
};

struct _${prefix}error_info {
  int code;
  int tag;
  ${prefix}arg_list *args;
  int index;
};

void ${prefix}parse(int, char **);
static void ${prefix}init_default_values();
static int ${prefix}scan_tokens(int, char **, ${prefix}token *);
static int ${prefix}scan_lopt_tokens(${prefix}token *, int *, char *);
static int ${prefix}sopt_token(char);
static int ${prefix}lopt_token(char *);
static int ${prefix}opt_token(char, char *);
static void ${prefix}set_token(${prefix}token *, int, int, const char *);
static int ${prefix}max_nargs(int, ${prefix}token *);
static void ${prefix}validate_tokens(int, ${prefix}token *);
static void ${prefix}parse_tokens(int, ${prefix}token *, int);
static void ${prefix}invoke_action(int, int, char **);
static void ${prefix}invoke_pos_action(int, char **);
static int ${prefix}opt_nargs(int);
static void ${prefix}convert_args(int, int, ${prefix}arg_list *, char **);
static int ${prefix}set_const(int, char *, ${prefix}arg *);
static void ${prefix}validate_selects(int, ${prefix}arg *);
static void ${prefix}free_args(${prefix}arg_list *);
static void ${prefix}set_default_values(${prefix}opt_info *, ${prefix}arg_list *);

static void ${prefix}error(const char *, ...);
static void ${prefix}raise(int, int, ${prefix}arg_list *, int);
static void ${prefix}handle_error();
static void ${prefix}print_error_msg(int, ${prefix}opt_info *, ${prefix}arg_list *, int);
static void ${prefix}print_cmd(const char *, ...);
static void ${prefix}eprintf(const char *, ...);
static void ${prefix}veprintf(const char *, va_list);

static void ${prefix}print_usage();
static void ${prefix}print_usage_and_exit(int);
static void ${prefix}print_version_and_exit(int);
static void ${prefix}print_help_and_exit(int);

static char *${cmd} = NULL;
static ${prefix}error_info *${prefix}handler = NULL;
static ${prefix}arg ${prefix}default_values[${nopts}][${max_noptargs}];

/* option actions */
${actions}

/* option table */
static ${prefix}opt_info ${prefix}opt_table[] = {
${opt_infos}
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

'''

C_FUNCS_LINE = line_control(frame.f_lineno)
C_FUNCS = '''
#ifndef ${PREFIX}MALLOC
#define ${PREFIX}MALLOC       malloc
#endif /* ${PREFIX}MALLOC */
#ifndef ${PREFIX}REALLOC
#define ${PREFIX}REALLOC      realloc
#endif /* ${PREFIX}REALLOC */
#ifndef ${PREFIX}FREE
#define ${PREFIX}FREE         free
#endif /* ${PREFIX}FREE*/

void
${prefix}parse(int argc, char **argv)
{
  int tok_size, max_nargs = 0;
  ${prefix}token *tokens;

  ${prefix}init_default_values();
  ${cmd} = (char *)${PREFIX}MALLOC(strlen(argv[0])+1);
  strcpy(${cmd}, argv[0]);
  --argc;
  ++argv;

  tok_size = ${prefix}scan_tokens(argc, argv, NULL);
  tokens = (${prefix}token *)${PREFIX}MALLOC(sizeof(${prefix}token) * tok_size);
  ${prefix}scan_tokens(argc, argv, tokens);
  ${prefix}validate_tokens(tok_size, tokens);
  
  max_nargs = ${prefix}max_nargs(tok_size, tokens);
  ${prefix}parse_tokens(tok_size, tokens, max_nargs);
}

static void
${prefix}init_default_values()
{
  static int inited = 0;

  if (inited)
    return;

$init_defvals
  inited = 1;
}

static int
${prefix}scan_tokens(int argc, char **argv, ${prefix}token *tokens)
{
  int tok_size = 0, tag = -1, scan_opts = 1;
  char *opt;

  while (argc > 0) {
    if (scan_opts) {
      /* "--" */
      if (strcmp(*argv, "--") == 0) {
        scan_opts = 0;

      /* "-" */
      } else if (strcmp(*argv, "-") == 0) {
        if (tokens != NULL)
          ${prefix}set_token(tokens, tok_size, ${PREFIX}MINUS1_TAG, "-");
        tok_size++;

        /* long option */
        } else if (strstr(*argv, "--") == *argv) {
        opt = *argv + 2;
        if (!${prefix}scan_lopt_tokens(tokens, &tok_size, opt)) {
          ${prefix}print_cmd("invalid option: --%s\\n", opt);
          ${prefix}print_usage_and_exit(1);
        }
  
      /* short options or long option */
      } else if (**argv == '-') {
        opt = *argv + 1;
  
        /* negative integer */
        if (isdigit(*opt)) {
          if (tokens != NULL)
            ${prefix}set_token(tokens, tok_size, ${PREFIX}ARG_TAG, *argv);
          tok_size++;
          
        } else if (!${prefix}scan_lopt_tokens(tokens, &tok_size, opt)) {
          while (*opt) {
            if ((tag = ${prefix}sopt_token(*opt)) > -1) {
              if (tokens != NULL)
                ${prefix}set_token(tokens, tok_size, tag, opt);
              tok_size++;
              opt++;
  
              /* argument */
              if (${prefix}opt_nargs(tag) > 0 && *opt) {
                if (tokens != NULL)
                  ${prefix}set_token(tokens, tok_size, ${PREFIX}ARG_TAG, opt);
                tok_size++;
                break;
              }
            } else {
              ${prefix}print_cmd("invalid option: -%c\\n", *opt);
              ${prefix}print_usage_and_exit(1);
            }
          }
        }

      /* argument */
      } else {
        if (tokens != NULL)
          ${prefix}set_token(tokens, tok_size, ${PREFIX}ARG_TAG, *argv);
        tok_size++;
      }

    /* argument */
    } else {
      if (tokens != NULL)
        ${prefix}set_token(tokens, tok_size, ${PREFIX}ARG_TAG, *argv);
      tok_size++;
    }

    argc--;
    argv++;
  }

  return tok_size;
}

static int
${prefix}sopt_token(char c)
{
  return ${prefix}opt_token(c, NULL);
}

static int
${prefix}scan_lopt_tokens(${prefix}token *tokens, int *sizep, char *arg)
{
  char *opt, *value;
  int tag;

  tag = ${prefix}lopt_token(arg);
  if (tag == -1)
    return 0;
  (*sizep)++;

  if ((value = strchr(arg, '=')) != NULL) {
    if (tokens != NULL) {
      opt = (char *)${PREFIX}MALLOC(value - arg + 1);
      strncpy(opt, arg, value - arg);
      opt[value - arg] = 0;
      ${prefix}set_token(tokens, *sizep-1, tag, opt);
      ${prefix}set_token(tokens, *sizep, ${PREFIX}ASSOC_ARG_TAG, value+1);
      ${PREFIX}FREE(opt);
    }
    (*sizep)++;
  } else if (tokens != NULL)
    ${prefix}set_token(tokens, *sizep-1, tag, arg);

  return 1;
}

static int
${prefix}lopt_token(char *s)
{
  return ${prefix}opt_token(0, s);
}

static int
${prefix}opt_token(char sopt, char *lopt)
{
  int i = 0;
  char *eq;
  ${prefix}opt_info *table = ${prefix}opt_table;

  while (table->sopt != 0 || table->lopt != NULL) {
    if (table->sopt && sopt) {
      if (table->sopt == sopt)
        return i;
    } else if (table->lopt && lopt) {
      if ((eq = strchr(lopt, '=')) != NULL) {
        if (lopt + strlen(table->lopt) == eq &&
            strstr(lopt, table->lopt) == lopt)
          return i;
      } else if (strcmp(lopt, table->lopt) == 0)
        return i;
    }
    table++;
    i++;
  }

  return -1;
}

static void
${prefix}set_token(${prefix}token *tokens, int tok_size, int tag, const char *value)
{
  tokens[tok_size].tag = tag;
  tokens[tok_size].value = (char *)${PREFIX}MALLOC(strlen(value)+1);
  strcpy(tokens[tok_size].value, value);
}

static int
${prefix}max_nargs(int tok_size, ${prefix}token *tokens)
{
  int i, max = 0, size = 0;

  for (i = 0; i < tok_size; i++) {
    if (tokens[i].tag == ${PREFIX}ASSOC_ARG_TAG) {
      if (max == 0)
        max = 1;
      size = 0;
    } else if (tokens[i].tag == ${PREFIX}ARG_TAG) {
      size++;
      if (size > max)
        max = size;
    } else
      size = 0;
  }
  if (size > max)
    max = size;

  return max;
}

static void
${prefix}validate_tokens(int tok_size, ${prefix}token *tokens)
{
  int multiples[${PREFIX}OPT_COUNT], i, tag;

  for (i = 0; i < ${PREFIX}OPT_COUNT; i++)
    multiples[i] = 0;

  for (i = 0; i < tok_size; i++) {
    tag = tokens[i].tag;
    if (tag != ${PREFIX}ARG_TAG) {
      if (multiples[tag] && !${prefix}opt_table[tag].multiple) {
        ${prefix}raise(${PREFIX}MULTIPLE_ERROR, tag, NULL, 0);
        break;
      } else
        multiples[tokens[i].tag] = 1;
    }
  }

  ${prefix}handle_error();
}

static void
${prefix}parse_tokens(int tok_size, ${prefix}token *tokens, int max)
{
  int i, argc, pos_argc, pos_invoked = 0, tag = -1;
  ${prefix}token t;
  ${prefix}opt_info *opt = NULL;
  char **args, **pos_args;

  args = (char **)${PREFIX}MALLOC(sizeof(char *) * max);
  pos_args = (char **)${PREFIX}MALLOC(sizeof(char *) * max);
  argc = 0;
  pos_argc = 0;
  for (i = 0; i < tok_size; i++) {
    t = tokens[i];

    /* argument */
    if (t.tag == ${PREFIX}ARG_TAG || t.tag == ${PREFIX}ASSOC_ARG_TAG) {
      /* option argument */
      if (tag > -1) {
        args[argc++] = t.value;
        if (!opt->var_args && argc >= opt->nargs) {
          ${prefix}invoke_action(tag, argc, args);
          tag = -1;
          argc = 0;
        }

      /* positional variable arguments */
      } else if (${prefix}opt_table[${PREFIX}POS_ARGS_TAG].var_args) {
        if (!pos_invoked) {
          if (max <= pos_argc) {
            max *= 2;
            pos_args = (char **)${PREFIX}REALLOC(pos_args, sizeof(char *) * max);
          }
          pos_args[pos_argc++] = t.value;
        } else
          ${prefix}print_usage_and_exit(1);

      /* positional argument */
      } else {
        pos_args[pos_argc++] = t.value;
        if (!${prefix}opt_table[${PREFIX}POS_ARGS_TAG].var_args &&
            pos_argc >= ${prefix}opt_table[${PREFIX}POS_ARGS_TAG].nargs) {
          ${prefix}invoke_pos_action(pos_argc, pos_args);
          pos_argc = 0;
          pos_invoked = 1;
        }
      }

    /* begin option */
    } else {
      /* invoke action of positional variable arguments */
      if (${prefix}opt_table[${PREFIX}POS_ARGS_TAG].var_args && !pos_invoked && pos_argc) {
        ${prefix}invoke_pos_action(pos_argc, pos_args);
        pos_invoked = 1;
      }

      if (tag > -1) {
        ${prefix}invoke_action(tag, argc, args);
        argc = 0;
      }

      if (!${prefix}opt_table[t.tag].var_args && ${prefix}opt_nargs(t.tag) == 0) {
        ${prefix}invoke_action(t.tag, 0, NULL);
        tag = -1;
      } else {
        tag = t.tag;
        opt = &${prefix}opt_table[t.tag];
      }
    }
  }

  /* invoke action of positional variable arguments */
  if (${prefix}opt_table[${PREFIX}POS_ARGS_TAG].var_args && !pos_invoked) {
    ${prefix}invoke_pos_action(pos_argc, pos_args);
    pos_invoked = 1;
  }

  if (tag > -1) {
    ${prefix}invoke_action(tag, argc, args);
    tag = -1;
    argc = 0;
  }

  if (!pos_invoked) {
    if (pos_argc >= ${prefix}opt_table[${PREFIX}POS_ARGS_TAG].nargs)
      ${prefix}invoke_pos_action(pos_argc, pos_args);
    else
      ${prefix}print_usage_and_exit(1);
  }
}

static int
${prefix}opt_nargs(int tag)
{
  return ${prefix}opt_table[tag].nargs;
}

static void
${prefix}invoke_action(int tag, int nargs, char **args)
{
  ${prefix}opt_info *opt;
  ${prefix}arg_list *cargs;

  opt = &${prefix}opt_table[tag];

   /* check number of arguments */
   if (!opt->var_args && ((opt->nargs - opt->ndefvals) > nargs))
     ${prefix}print_usage_and_exit(1);

  /* print deprecation message */
  if (opt->dep != NULL)
    ${prefix}print_cmd("%s\\n", opt->dep);

  cargs = (${prefix}arg_list *)${PREFIX}MALLOC(sizeof(${prefix}arg_list));
  cargs->arg_type = opt->arg_type;
  cargs->nargs = nargs;
  cargs->args = (${prefix}arg *)${PREFIX}MALLOC(sizeof(${prefix}arg) * nargs);

  ${prefix}convert_args(tag, nargs, cargs, args);
  ${prefix}handle_error();

  if (opt->nargs > nargs)
    ${prefix}set_default_values(opt, cargs);

  /* variable arguments */
  if (opt->var_args) {
    cargs->nvargs = nargs - opt->nargs;
    cargs->vargs = cargs->args + opt->nargs;
  }

  if (opt->action != NULL) {
    opt->action(cargs);
  }

  ${prefix}free_args(cargs);
}

static void
${prefix}invoke_pos_action(int nargs, char **args)
{
  ${prefix}invoke_action(${PREFIX}POS_ARGS_TAG, nargs, args);
}

static void
${prefix}convert_args(int tag, int nargs, ${prefix}arg_list *cargs, char **args)
{
  int i;
  char *arg;
  char *earg = NULL;
  ${prefix}arg *carg;

  for (i = 0; i < nargs; i++) {
    arg = args[i];
    carg = &cargs->args[i];
    errno = 0;
    if (${prefix}set_const(tag, arg, carg)) {
      ${prefix}validate_selects(tag, carg);
      continue;
   }

    switch (cargs->arg_type) {
    case ${PREFIX}STR_TYPE:
      carg->sval = (char *)${PREFIX}MALLOC(strlen(arg) + 1);
      strcpy(carg->sval, arg);
      break;

    case ${PREFIX}INT_TYPE:
      carg->lval = strtol(arg, &earg, 0);
      if (errno == ERANGE) {
        if (carg->lval == LONG_MAX || carg->lval == LONG_MIN) {
          ${prefix}raise(${PREFIX}RANGE_ERROR, tag, cargs, i);
          return;
        }
        else
          ${prefix}error("${prefix}convert_args(): unknown errno %d", errno);
      } else if (*earg != 0) {
        ${prefix}raise(${PREFIX}CONVERT_ERROR, tag, cargs, i);
        return;
      }
      break;

    case ${PREFIX}UINT_TYPE:
      carg->ulval = strtoul(arg, &earg, 0);
      if (errno == ERANGE) {
        if (carg->ulval == ULONG_MAX) {
          ${prefix}raise(${PREFIX}RANGE_ERROR, tag, cargs, i);
          return;
        }
        else
          ${prefix}error("${prefix}convert_args(): unknown errno %d", errno);
      } else if (*earg != 0) {
        ${prefix}raise(${PREFIX}CONVERT_ERROR, tag, cargs, i);
        return;
      }
      break;

    case ${PREFIX}FLOAT_TYPE:
      carg->dval = atof(arg);
      break;

    default:
      ${prefix}error("${prefix}convert_args(): unknown argument type -- %d",
               cargs->arg_type);
    }
    ${prefix}validate_selects(tag, carg);
  }
}

static int
${prefix}set_const(${PREFIX}VAR(int tag), ${PREFIX}VAR(char *name), ${PREFIX}VAR(${prefix}arg *arg))
{
${set_const}
  return 0;
}

static void
${prefix}validate_selects(${PREFIX}VAR(int tag), ${PREFIX}VAR(${prefix}arg *arg))
{
${validate_selects}
}

static void
${prefix}set_default_values(${prefix}opt_info *opt, ${prefix}arg_list *args)
{
  int i;
  const char *csval;

  for (i = args->nargs; i < opt->nargs; i++) {
    switch (opt->arg_type) {
    case ${PREFIX}STR_TYPE:
      csval = ${prefix}default_values[opt->tag][i].csval;
      args->args[i].sval = (char *)${PREFIX}MALLOC(strlen(csval)+1);
      strcpy(args->args[i].sval, csval);
      break;
    case ${PREFIX}INT_TYPE:
      args->args[i].lval = ${prefix}default_values[opt->tag][i].lval;
      break;
    case ${PREFIX}UINT_TYPE:
      args->args[i].ulval = ${prefix}default_values[opt->tag][i].ulval;
      break;
    case ${PREFIX}FLOAT_TYPE:
      args->args[i].dval = ${prefix}default_values[opt->tag][i].dval;
      break;
    default:
      ${prefix}error("${prefix}set_default_value(): unknown argument type");
      exit(1);
    }
  }
}

static void
${prefix}free_args(${prefix}arg_list *args)
{
  int i;
  ${prefix}arg *arg;

  for (i = 0; i < args->nargs; i++) {
    arg = &args->args[i];
    switch (args->arg_type) {
    case ${PREFIX}STR_TYPE:
      ${PREFIX}FREE(arg->sval);
      break;

    case ${PREFIX}INT_TYPE: case ${PREFIX}UINT_TYPE: case ${PREFIX}FLOAT_TYPE:
      /* do nothing */
      break;

    default:
      ${prefix}error("${prefix}free_args(): unknown argument type -- %d", args->arg_type);
    }
  }
  ${PREFIX}FREE(args);
}

static void
${prefix}error(const char *format, ...)
{
  va_list list;

  ${prefix}print_cmd(NULL);
  va_start(list, format);
  ${prefix}veprintf(format, list);
  ${prefix}eprintf("\\n");
  va_end(list);
  exit(EXIT_FAILURE);
}

static void
${prefix}raise(int code, int tag, ${prefix}arg_list *args, int index)
{
  ${prefix}handler = (${prefix}error_info *)${PREFIX}MALLOC(sizeof(${prefix}error_info));
  ${prefix}handler->code = code;
  ${prefix}handler->tag = tag;
  ${prefix}handler->args = args;
  ${prefix}handler->index = index;
}

static void
${prefix}handle_error()
{
  ${prefix}opt_info *opt;

  if (${prefix}handler != NULL) {
    ${prefix}print_cmd(NULL);
    opt = &${prefix}opt_table[${prefix}handler->tag];
    if (opt->sopt && opt->lopt)
      ${prefix}eprintf("-%c, --%s: ", opt->sopt, opt->lopt);
    else if (opt->sopt)
      ${prefix}eprintf("-%c: ", opt->sopt);
    else if (opt->lopt)
      ${prefix}eprintf("--%s: ", opt->lopt);
    else
      ${prefix}eprintf("unknown option (%d): ", ${prefix}handler->tag);
    ${prefix}print_error_msg(${prefix}handler->code, opt, ${prefix}handler->args, ${prefix}handler->index);
    ${prefix}eprintf("\\n");
    exit(EXIT_FAILURE);
  }
}

static void
${prefix}print_error_msg(int code, ${PREFIX}VAR(${prefix}opt_info *opt), ${prefix}arg_list *args, int i)
{
  switch (code) {
  case ${PREFIX}RANGE_ERROR:
    if (args->nargs > 1)
      ${prefix}eprintf("value of argument %d is out of range", i);
    else
      ${prefix}eprintf("value is out of range");
    break;

  case ${PREFIX}CONVERT_ERROR:
    if (args->nargs > 1)
      ${prefix}eprintf("value of argument %d is invalid", i);
    else
      ${prefix}eprintf("value is invalid");
    break;
    
  case ${PREFIX}MULTIPLE_ERROR:
    ${prefix}eprintf("cannot be used more than once");
    break;

  case ${PREFIX}SELECT_ERROR:
    ${prefix}eprintf("the selection value is invalid");
    break;

  default:
    ${prefix}eprintf("unknown error");
  }
}

static void
${prefix}print_cmd(const char *format, ...)
{
  va_list list;

  ${prefix}eprintf("%s: ", ${cmd});
  if (format != NULL) {
    va_start(list, format);
    ${prefix}veprintf(format, list);
    va_end(list);
  }
}

static void
${prefix}eprintf(const char *format, ...)
{
  va_list list;

  va_start(list, format);
  ${prefix}veprintf(format, list);
  va_end(list);
}

static void
${prefix}veprintf(const char *format, va_list list)
{
  vfprintf(stderr, format, list);
}

'''

C_PRINT_USAGE_AND_EXIT_LINE = line_control(frame.f_lineno)
C_PRINT_USAGE_AND_EXIT = '''static void
${prefix}print_usage()
{
  printf("Usage: %s $usage\\n", $cmd);
}

static void
${prefix}print_usage_and_exit(int code)
{
  ${prefix}print_usage();
  exit(code);
}

'''

C_PRINT_VERSION_AND_EXIT_LINE = line_control(frame.f_lineno)
C_PRINT_VERSION_AND_EXIT = '''static void
${prefix}print_version_and_exit(int code)
{
  printf("$version\\n");
  exit(code);
}

'''

C_PRINT_HELP_AND_EXIT_LINE = line_control(frame.f_lineno)
C_PRINT_HELP_AND_EXIT = '''static void
${prefix}print_help_and_exit(int code)
{
  static const char *options[] = {
$helps
    NULL,
  };

  const char **p = options;
  ${prefix}print_usage();
  printf("\\nOptions:\\n");
  while (*p)
    printf("  %s\\n", *p++);
  exit(code);
}

'''


#
# running command
#

cmd = None
options = {}

def run(argv):
    global cmd, options
    cmd = argv[0]
    p = optparse.OptionParser(usage=USAGE, version=VERSION)
    p.add_option('-d', '--debug', action='store_true',
                 help='debug mode')
    p.add_option('-v', '--verbose', action='store_true',
                 help='verbose mode')
    p.add_option('-V', action='version',
                 help='print version and exit')
    p.add_option('-o', '--output',
                 help='output source file path')
    p.add_option('-c', '--c-extension', default='c', dest='c_ext',
                 metavar='EXT',
                 help="extension of C file (default=`c')")
    p.add_option('-p', '--symbol-prefix', default='lg_',
                 dest='sym_prefix', metavar='PREFIX',
                 help="prefix of parser symbols (default=`lg_')")
    p.add_option('-l', '--no-lines', action='store_false',
                 dest='lines', default=True,
                 help="do not put #line commands in the parser")
    options, args = p.parse_args(argv[1:])

    if len(args) == 0:
        p.print_usage()
        sys.exit(1)
    
    lg = ConfigParser()
    for arg in args:
        if os.path.exists(arg):
            lg.parse(arg)
        else:
            print_error('%s: No such file' % arg)

    if not options.output:
        options.output = os.path.splitext(args[0])[0] + '.' + options.c_ext

    CGenerator(lg.parser, options.output).generate()

def print_error(msg):
    print "%s: %s" % (cmd, msg)
    exit()


#
# parsing configuration files
#

class StringScanner(object):
    
    def __init__(self, string):
        self.string = string
        self.rest = string
        self.location = 0
        self.matched = None

    def line_location(self):
        scanned = self.string[:self.location]
        line = re.split(r'\r\n|\r|\n', scanned)[-1]
        return len(line) + 1
    
    def peek(self, length):
        return self.rest[:length]
    
    def scan(self, pattern, advances=True):
        self.matched = pattern.match(self.rest)
        if self.matched:
            matched = self.matched.group(0)
            if advances:
                self.location += self.matched.end()
                self.rest = self.rest[self.matched.end():]
            return matched
    
    def scan_until(self, pattern, advances=True):
        self.matched = pattern.search(self.rest)
        if self.matched:
            matched = self.matched.group(0)
            until = self.rest[:self.matched.end()]
            if advances:
                self.location += self.matched.end()
                self.rest = self.rest[self.matched.end():]
            return until
    
    def scan_block(self, begin_re, end_re, includes=False):
        if not self.check(begin_re):
            return
        
        s = StringIO.StringIO()
        count = 0
        while not self.eos():
            begin = self.scan(begin_re)
            if begin:
                if count == 0:
                    if includes:
                        s.write(begin)
                else:
                    s.write(begin)
                count += 1
                continue

            end = self.scan(end_re)
            if end:
                count -= 1
                if count == 0:
                    if includes:
                        s.write(end)
                    return s.getvalue()
                else:
                    s.write(end)
            else:
                m = self.scan(STR_RE)
                if m:
                    s.write(m)
                    continue
                m = self.scan(CHAR_RE)
                if m:
                    s.write(m)
                    continue
                s.write(self.getc())

    def check(self, pattern):
        return self.scan(pattern, False)
    
    def check_until(self, pattern):
        return self.scan_until(pattern, False)
    
    def terminate(self):
        self.rest = ''
        self.location = len(self.string)
        self.matched = None
    
    def getc(self):
        c = self.rest[0:1]
        self.rest = self.rest[1:]
        self.location += 1
        self.matched = None
        return c
    
    def eos(self):
        """at end of string"""
        return not bool(self.rest)
    
    def bol(self):
        """at begin of line"""
        return self.location == 0 or self.string[self.location-1] == '\n'


D  = r'[0-9]'
L  = r'[a-zA-Z_]'
H  = r'[a-fA-F0-9]'
E  = r'[Ee][+-]?%s+' % D
FS = r'(f|F|l|L)'
IS = r'(u|U|l|L)*'

IGNORE_RE     = re.compile('\s')
BEGIN_COMMENT_RE = re.compile('\A/\*')
END_COMMENT_RE = re.compile('\*/')

# directives
BEGIN_C_DECL_DT_RE = re.compile('\A%\s*{', re.M)
END_C_DECL_DT_RE = re.compile('\A%\s*}', re.M)
PROGRAM_DT_RE = re.compile('\A%\s*program', re.M)
VERSION_DT_RE = re.compile('\A%\s*version', re.M)
USAGE_DT_RE = re.compile('\A%\s*usage', re.M)
OPTION_DT_RE = re.compile('\A%\s*%', re.M)
UNKNOWN_DT_RE = re.compile('\A%\s*[^\s]+', re.M)

# identifiers
ID_RE = re.compile(r'\A[A-Za-z_][\w_]*')
SOPT_RE = re.compile(r'\A-[A-Za-z]')
LOPT_RE = re.compile(r'\A--[A-Za-z][\w_-]*')
POS_RE = re.compile(r'\A\+')
MINUS1_RE = re.compile(r'\A-')

# string literal
STR_RE = re.compile(r'\AL?\"([^\\\n]|(\\.))*?\"', re.M)
CHAR_RE = re.compile(r'\A(L)?\'([^\\\n]|(\\.))*?\'', re.M)

# integer literal
i_hex = r'0[xX]%s+%s?' % (H, IS)
i_oct = r'0\d+%s?' % IS
i_dec = r'\d+%s?' % IS
INT_RE = re.compile(r'\A(%s)|(%s)|(%s)' % (i_hex, i_oct, i_dec))

# floating literal
f_ex = r'%s+%s%s?' % (D, E, FS)
f_point1 = r'%s*\.%s+(%s)?%s?' % (D, D, E, FS)
f_point2 = r'%s+\.%s*(%s)?%s?' % (D, D, E, FS)
FLOAT_RE = re.compile(r'\A(%s)|(%s)|(%s)' % (f_ex, f_point1, f_point2))

COMMA_RE = re.compile(r'\A,')
COLON_RE = re.compile(r'\A:')
LBRACE_RE = re.compile(r'\A{')
RBRACE_RE = re.compile(r'\A}')
LBRACKET_RE = re.compile(r'\A\[')
RBRACKET_RE = re.compile(r'\A\]')
ELLIPSIS_RE = re.compile(r'\.\.\.')


class ConfigToken(object):

    C_DECL_DT, PROGRAM_DT, VERSION_DT, USAGE_DT, OPTION_DT, \
               POS, MINUS1, SOPT, LOPT, ID, STRING, INT, FLOAT, CODE_BLOCK, \
               COMMA, COLON, LBRACE, RBRACE, ELLIPSIS = range(1, 20)
    READABLE_NAMES = [None, 'C declaration', '%program', '%version',
                      '%usage', 'option rules',
                      'identifier', 'option', 'string', 'integer', 'float',
                      'code block', 'comma', 'colon', '{', '}', '...']
    ARG_VALUES = (ID, STRING, INT, FLOAT)

    LG_DT_RES = ((PROGRAM_DT_RE, PROGRAM_DT),
                 (VERSION_DT_RE, VERSION_DT),
                 (USAGE_DT_RE, USAGE_DT))

    type = None
    value = None

    @classmethod
    def readable_name_for(cls, type):
        return cls.READABLE_NAMES[type]
    
    def readable_name(self, use_id_value=False):
        if use_id_value and self.type == ConfigToken.ID:
            return self.value
        else:
            return self.__class__.readable_name_for(self.type)

    def satisfied(self):
        return bool(self.type)

    def type_name(self):
        for attr in dir(ConfigToken):
            if not attr.startswith('_') and attr.isupper():
                if getattr(self, attr) == self.type:
                    return attr
        raise ValueError, 'unknown type -- %s' % self.type

    def __repr__(self):
        if self.value:
            return "<%s:%s>" % (self.type_name(),
                                repr(shorten(self.value, 10)))
        else:
            return "<%s>" % self.type_name()

    def py_value(self):
        if self.type == ConfigToken.ID:
            return self.value
        elif self.type == ConfigToken.STRING:
            if self.value.startswith('L'):
                s = self.value[1:]
            else:
                s = self.value
            return eval(s)
        elif self.type == ConfigToken.INT:
            return int(self.value)
        elif self.type == ConfigToken.FLOAT:
            return float(self.value)
        elif self.type == ConfigToken.CODE_BLOCK:
            return CodeBlock(self.lineno, self.value)
        else:
            raise ValueError, 'not supported %s' % self.type_name()

    def is_arg_value(self):
        return self.type in self.ARG_VALUES


class ConfigScanner(StringScanner):

    def __init__(self, path):
        self.path = path
        StringScanner.__init__(self, open(path).read())
        self.option_dts = 0
        self.stop = False
        self.lineno = 1
        self.stocks = []

    def back(self, t):
        self.stocks.insert(0, t)
        
    def next(self):
        if self.stocks:
            tok = self.stocks.pop()
            print_debug("stocked token:%d: %s" % (tok.lineno, repr(tok)))
            return tok
        elif self.stop:
            return
        else:
            s = self.scan_no_effects()
            if s:
                self.lineno += s.count('\n')
            lo = self.line_location()
            tok = self._next()
            tok.location = lo
            tok.lineno = self.lineno
            if tok.value:
                self.lineno += tok.value.count('\n')
            print_debug("token:%d: %s" % (tok.lineno, repr(tok)))
            return tok

    def _next(self):
        tok = ConfigToken()
        while not self.eos():
            if self.scan_c_decl(tok): return tok
            elif self.scan_lg_decl_dts(tok): return tok
            elif self.scan_option(tok): return tok
            elif self.scan_id(tok): return tok
            elif self.scan_literals(tok): return tok
            elif self.scan_marks(tok): return tok
            else:
                break
        self.scan_error("unexpected char `%s'" % self.peek(1))

    # comments, spaces
    def scan_no_effects(self):
        s = StringIO.StringIO()
        while True:
            m = self.scan(BEGIN_COMMENT_RE)
            if m:
                s.write(m)
                m = self.scan_until(END_COMMENT_RE)
                if m:
                    s.write(m)
                else:
                    self.no_close_error('/*', '*/')
                continue
            m = self.scan(IGNORE_RE)
            if m:
                s.write(m)
                continue
            break
        return s.getvalue()

    def no_close_error(self, open, close):
        self.scan_error("`%s' must be closed with `%s'" % (open, close))
        
    def eof_error_if(self):
        if self.eos():
            self.scan_error("unexpected end of file while parsing")

    def scan_c_decl(self, tok):
        tok.value = self.scan_block_or_error(BEGIN_C_DECL_DT_RE,
                                             END_C_DECL_DT_RE,
                                             '%{', '%}')
        if tok.value:
            tok.type = ConfigToken.C_DECL_DT
            return True
            
    def scan_block_or_error(self, begin_re, end_re, begin_str, end_str):
        if self.check(begin_re):
            s = self.scan_block(begin_re, end_re)
            if s:
                return s
            else:
                self.no_close_error(begin_str, end_str)
    
    # scan lineguide declaration directives
    def scan_lg_decl_dts(self, tok):
        for pat, type in ConfigToken.LG_DT_RES:
            if self.scan(pat):
                tok.type = type
                return True

        if self.scan(OPTION_DT_RE):
            tok.type = ConfigToken.OPTION_DT
            self.option_dts += 1
            if self.option_dts < 3:
                return True
            else:
                # not used
                self.scan_error("option rules are already declared")
        
        s = self.scan(UNKNOWN_DT_RE)
        if s:
            self.scan_error("unknown declarator -- %s" % s)

    def scan_option(self, tok):
        return self.scan_simples(tok, [[SOPT_RE, ConfigToken.SOPT],
                                       [LOPT_RE, ConfigToken.LOPT],
                                       [POS_RE, ConfigToken.POS],
                                       [MINUS1_RE, ConfigToken.MINUS1]])
    
    def scan_simples(self, tok, rules):
        for pattern, type in rules:
            if self.scan_simple(tok, pattern, type):
                return True
        return False
    
    def scan_simple(self, tok, pattern, type):
        tok.value = self.scan(pattern)
        if tok.value:
            tok.type = type
            return True

    def scan_id(self, tok):
        tok.value = self.scan(ID_RE)
        if tok.value:
            tok.type = ConfigToken.ID
            return True

    LITERAL_RES = ((STR_RE, ConfigToken.STRING),
                   (FLOAT_RE, ConfigToken.FLOAT),
                   (INT_RE, ConfigToken.INT))
    
    def scan_literals(self, tok):
        for pat, type in self.LITERAL_RES:
            tok.value = self.scan(pat)
            if tok.value:
                tok.type = type
                return True
        if self.scan_code_block(tok): return True

    def scan_code_block(self, tok):
        tok.value = self.scan_block_or_error(LBRACE_RE, RBRACE_RE, '{', '}')
        if tok.value:
            tok.type = ConfigToken.CODE_BLOCK
            return True

    def scan_marks(self, tok):
        if self.scan(COMMA_RE):
            tok.type = ConfigToken.COMMA
        elif self.scan(COLON_RE):
            tok.type = ConfigToken.COLON
        elif self.scan(ELLIPSIS_RE):
            tok.type = ConfigToken.ELLIPSIS
        return tok.satisfied()
    
    def scan_error(self, msg):
        s = self.string[:self.location]
        lines = s.count('\n') + 1
        try:
            chars = len(s[s.rindex('\n'):]) + 1
        except ValueError:
            chars = 1
        print "%s:%d:%d: %s" % (self.path, lines, chars, msg)
        exit(1)


class OptionTypeError(StandardError):

    def __init__(self, *tokens):
        StandardError.__init__(self)
        self.tokens = tokens


LG_DECL_STATE, OPT_STATE, LOPT_STATE, \
SOPT_ARG_STATE, LOPT_ARG_STATE, POS_ARG_STATE, \
OPT_ARG_END_STATE, OPT_ATTR_STATE, OPT_ATTR_END_STATE, \
OPT_ACTION_STATE, ADD_CODE_STATE = range(0, 11)

class ConfigParser(object):
    
    def __init__(self):
        self.parser = OptionParser()
        
    def parse(self, path):
        self.path = path
        self.sc = ConfigScanner(path)
        self.state = LG_DECL_STATE
        self.parse_init()
        table = [self.decl_state, self.opt_state, self.lopt_state,
                 self.sopt_arg_state, self.lopt_arg_state,
                 self.pos_arg_state, self.opt_arg_end_state,
                 self.opt_attr_state, self.opt_attr_end_state,
                 self.opt_action_state]
        while not self.sc.eos() and self.state != ADD_CODE_STATE:
            t = self.sc.next()
            s = table[self.state](t)
            if s == ADD_CODE_STATE:
                break
            elif s is not None:
                self.state = s
        self.parser.add_code(path, self.sc.lineno, self.sc.rest)                

    def parse_init(self):
        self.sopt = None
        self.lopt = None
        self.sargs = []
        self.largs = []
        self.pargs = []
        self.args = None
        self.vargs = False
        self.pos = False
        self.minus1 = False
        self.attrs = {}

    def print_state(self, s):
        print_debug("state: %s" % s)

    def decl_state(self, t):
        self.print_state('DECL')
        if t.type in LG_DECLS:
            decl = LG_DECLS[t.type]
            decl.parse(self, self.parser, t)
        elif t.type == ConfigToken.OPTION_DT:
            print_debug("begin parsing option rules")
            return OPT_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def opt_state(self, t):
        self.print_state('OPT')
        self.vargs = False
        self.opt = t
        if t.type == ConfigToken.POS:
            self.pos = True
            self.args = self.pargs
            return POS_ARG_STATE
        elif t.type == ConfigToken.MINUS1:
            self.minus1 = True
            self.args = []
            return OPT_ARG_END_STATE
        elif t.type == ConfigToken.SOPT:
            if self.sopt:
                self.duplicate_error(t.lineno, 'short')
            else:
                self.sopt = t.value
                self.args = self.sargs
                return SOPT_ARG_STATE
        elif t.type == ConfigToken.LOPT:
            self.lopt = t.value
            self.args = self.largs
            return LOPT_ARG_STATE
        elif t.type == ConfigToken.OPTION_DT:
            print_debug("end parsing option rules")
            return ADD_CODE_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def lopt_state(self, t):
        self.print_state('LOPT')
        if t.type == ConfigToken.LOPT:
            self.lopt = t.value
            self.args = self.largs
            return LOPT_ARG_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def sopt_arg_state(self, t):
        self.print_state('SOPT_ARG')
        if t.type == ConfigToken.ID:
            self.args.append(t.value)
        elif t.type == ConfigToken.COMMA:
            return LOPT_STATE
        elif t.type == ConfigToken.ELLIPSIS:
            self.vargs = True
            return OPT_ARG_END_STATE
        elif t.type == ConfigToken.COLON:
            return OPT_ATTR_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def lopt_arg_state(self, t):
        self.print_state('LOPT_ARG')
        if t.type == ConfigToken.ID:
            self.args.append(t.value)
            if (self.sargs and
                (len(self.sargs) < len(self.args) or
                 self.sargs[:len(self.args)] != self.args)):
                self.opt_args_error(t.lineno)
        elif t.type == ConfigToken.ELLIPSIS:
            if self.sargs and self.vargs is False:
                self.opt_args_error(t.lineno)
            else:
                self.vargs = True
                return OPT_ARG_END_STATE
        elif t.type == ConfigToken.COLON:
            return OPT_ATTR_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def opt_args_error(self, lineno):
        self.error(lineno, "arguments of short option and long option are different")

    def pos_arg_state(self, t):
        self.print_state('POS_ARG')
        if t.type == ConfigToken.ID:
            self.args.append(t.value)
        elif t.type == ConfigToken.ELLIPSIS:
            self.vargs = True
            return OPT_ARG_END_STATE
        elif t.type == ConfigToken.COLON:
            return OPT_ATTR_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def opt_arg_end_state(self, t):
        self.print_state('OPT_ARG_END')
        if t.type == ConfigToken.COLON:
            return OPT_ATTR_STATE
        else:
            self.parse_error(t.lineno, t.location)

    def opt_attr_state(self, t):
        self.print_state('OPT_ATTR')
        if t.type == ConfigToken.ID:
            name = t.value
            opt = OPTION_ATTRS.get(name)
            if opt:
                self.attrs[name] = opt.scan_arg_tokens(self, t)
                return OPT_ATTR_END_STATE
            else:
                self.error(t.lineno, "unknown option attribute `%s'" % name)
        elif t.type == ConfigToken.CODE_BLOCK:
            return self.opt_action_state(t)
        else:
            self.parse_error(t.lineno, t.location)

    def opt_attr_end_state(self, t):
        self.print_state('OPT_ATTR_END')
        if t.type == ConfigToken.COMMA:
            return OPT_ATTR_STATE
        elif t.type == ConfigToken.CODE_BLOCK:
            return self.opt_action_state(t)
        else:
            self.parse_error(t.lineno, t.location)
        
    def opt_action_state(self, t):
        self.print_state('OPT_ACTION')
        action = None
        if t.type == ConfigToken.CODE_BLOCK:
            self.validate_action(len(self.args), t)
            action = CodeBlock(t.lineno, t.value)
        else:
            self.parse_error(t.lineno, t.location)

        # add option
        if self.pos:
            opt = self.parser.set_pos(self.pargs, self.vargs,
                                      self.path, action, **self.attrs)
        elif self.minus1:
            opt = self.parser.set_minus1(self.path, action, **self.attrs)
        else:
            opt = self.parser.add_option(self.sopt, self.lopt, self.args,
                                         self.vargs, self.path, action,
                                         **self.attrs)
        opt.validate(self)
        self.parse_init()
        return OPT_STATE

    def error(self, lineno, msg):
        print "%s:%d: %s" % (self.path, lineno, msg)
        exit(1)

    def parse_error(self, lineno, location):
        print "%s:%d:%d: parse error" % (self.path, lineno, location)
        exit(1)

    def eof_error(self):
        print "%s: unexpected end of file while parsing" % self.path
        exit(1)

    def invalid_option_error(self, lineno, value):
        self.error(lineno, "invalid option `%s'" % value)

    def duplicate_error(self, lineno, name):
        self.error(lineno, "%s options are duplicated" % name)
        
    def both_options_error(self, lineno):
        self.error(lineno, "cannot define normal options and special options at the same rule")

    def print_parsed_option(self, sopt, sargs, lopt, largs, spopt, spargs, vargs):
        if options.verbose:
            s = 'option: '
            if spopt:
                s += self.verbose_option_decl(spopt, spargs, vargs)
            else:
                if sopt:
                    s += self.verbose_option_decl(sopt, sargs, vargs)
                if lopt:
                    if sopt:
                        s += ', '
                    s += self.verbose_option_decl(lopt, largs, vargs)
            print_debug(s)

    def verbose_option_decl(self, name, args, vargs):
        if args:
            return '%s %s %s' % (name, ' '.join(args), '...' if vargs else '')
        else:
            return name

    def validate_action(self, nargs, code_t):
        for m in re.finditer('\$(\d+)', code_t.value):
            n = int(m.group(1))
            if n > nargs:
                if nargs == 0:
                    rg = '$n cannot be used'
                elif nargs == 1:
                    rg = '$1 only'
                else:
                    rg = '$1-$%d' % nargs
                self.error(code_t.lineno,
                           "`$%d' is too large (%s)" % (n, rg))


#
# declaration description
#

class ArgumentType(object):

    pos_types = []
    opt_types = []
    var_type = []

    @classmethod
    def scan_args(cls, confp, t):
        return cls.py_values(cls.scan_arg_tokens(confp, t))
    
    @classmethod
    def py_values(self, ts):
        return [t.py_value() for t in ts]

    @classmethod
    def scan_arg_tokens(cls, confp, t):
        pos_ts = []
        opt_ts = []
        var_ts = []
        ts = cls._scan_args(confp)
        if cls.pos_types:
            pos_ts, ts = cls.scan_pos_args(confp, t, ts)
        if cls.opt_types:
            opt_ts, ts = cls.scan_opt_args(confp, t, ts)
        if cls.var_type:
            var_ts = cls.scan_var_args(confp, t, ts)
        if ts:
            pass # error
        return pos_ts + opt_ts + var_ts

    @classmethod
    def _scan_args(cls, confp):
        ts = []
        next = confp.sc.next()
        while next and next.is_arg_value():
            ts.append(next)
            next = confp.sc.next()
        if next:
            confp.sc.back(next)
        return ts

    @classmethod
    def scan_pos_args(cls, confp, opt_t, ts):
        lpos = len(cls.pos_types)
        if lpos > len(ts):
            if cls.opt_types or cls.var_type:
                degree = 'at least'
            else:
                degree = 'exactly'
            suffix = 's' if lpos > 1 else ''
            msg = "`%s' takes %s %d argument%s (%d given)" % \
                  (t.readable_name(True), degree, lpos, suffix, len(ts))
            confp.error(t.lineno, msg)

        for i, t in enumerate(ts):
            mismatch = True
            for type in cls.pos_types[i]:
                if t.type == type:
                    mismatch = False
                    break
            if mismatch:
                print_debug('scan_pos_args(): type error')
                cls.type_error(confp, opt_t, i+1)

        return ts[:lpos], ts[lpos:]

    @classmethod
    def scan_opt_args(cls, confp, opt_t, ts):
        lopt = len(cls.opt_types)
        for i, t in enumerate(ts):
            mismatch = True
            for type in cls.opt_types[i]:
                if t.type == type:
                    mismatch = False
                    break
            if mismatch:
                print_debug('scan_opt_args(): type error')
                cls.type_error(confp, opt_t, i+len(cls.pos_types)+1)
        return ts[:lopt], ts[lopt:]

    @classmethod
    def scan_var_args(cls, confp, opt_t, ts):
        for i, t in enumerate(ts):
            mismatch = True
            for type in cls.var_type:
                if t.type == type:
                    mismatch = False
                    break
            if mismatch:
                print_debug('scan_var_args(): type error')
                cls.type_error(confp, opt_t,
                                i+len(cls.pos_types)+len(cls.opt_types)+1)
        return ts

    @classmethod
    def type_error(cls, confp, t, nargs):
        msg = "passing argument %d of `%s' must be " % \
              (nargs, t.readable_name(True))
        if cls.pos_types:
            types = cls.pos_types[nargs-1]
        elif cls.opt_types:
            types = cls.opt_types[nargs-1]
        else:
            types = cls.var_type

        names = [ConfigToken.readable_name_for(type)
                 for type in types]
        if len(names) > 1:
            msg += ', '.join(names[:-1])
            msg += ' or %s' % names[-1]
        else:
            msg += names[0]
        confp.error(t.lineno, msg)


class Declaration(ArgumentType):

    def parse(self, confp, optp, t):
        self._parse(confp, optp, t, *self.scan_args(confp, t))

    def _parse(self, confp, optp, t, *args):
        raise NotImplementedError


class CDeclaration(Declaration):

    def _parse(self, confp, optp, t):
        print_debug("%s:%d: C declaration" % \
                    (confp.path, t.lineno))
        optp.c_decls.append([t.lineno, confp.path, t.value])


class ProgramDeclaration(Declaration):

    pos_types = [[ConfigToken.STRING]]
    
    def _parse(self, confp, optp, t, name):
        print_debug("parse %program")
        optp.program = name


class VersionDeclaration(Declaration):

    pos_types = [[ConfigToken.STRING]]
    
    def _parse(self, confp, optp, t, version):
        print_debug("parse %version")
        optp.version = version


class UsageDeclaration(Declaration):

    pos_types = [[ConfigToken.STRING]]
    
    def _parse(self, confp, optp, t, usage):
        print_debug("parse %usage")
        optp.usage = usage


#
# option attribute description
#

STR_ARG_TYPE, INT_ARG_TYPE, UINT_ARG_TYPE, FLOAT_ARG_TYPE = range(0,4)
ARG_TYPES = {'str':STR_ARG_TYPE,
             'int':INT_ARG_TYPE,
             'uint':UINT_ARG_TYPE,
             'float':FLOAT_ARG_TYPE}
C_DEFVAL_MEMBER = ['csval', 'lval', 'ulval', 'dval']
C_ARG_MEMBER = ['sval', 'lval', 'ulval', 'dval']

class OptionAttribute(ArgumentType):

    name = None
    option_attr = None
    option_default_value = None

    def validate_unit(self, confp, opt):
        pass
    
    def validate_depend(self, confp, opt):
        pass
    
    def init_option(self, opt):
        self.opt = opt
        opt.attrs[self.name] = self
        setattr(opt, self.option_attr, self._value_to_init())

    def _value_to_init(self):
        raise NotImplementedError


class HelpOptionAttribute(OptionAttribute):

    name = 'help'
    option_attr = 'help'
    option_default_value = '(no description)'
    pos_types = [[ConfigToken.ID, ConfigToken.STRING]]

    def __init__(self, msg):
        self.msg = msg

    def _value_to_init(self):
        return self.msg


class DeprecateOptionAttribute(OptionAttribute):

    name = 'deprecate'
    option_attr = 'deprecate'
    option_default_value = None
    
    pos_types = [[ConfigToken.ID, ConfigToken.STRING]]

    def __init__(self, msg):
        self.msg = msg

    def _value_to_init(self):
        return self.msg


class TypeOptionAttribute(OptionAttribute):

    name = 'type'
    option_attr = 'arg_type'
    option_default_value = STR_ARG_TYPE
    pos_types = [[ConfigToken.ID]]

    def validate_unit(self, confp, opt):
        try:
            self.type = ARG_TYPES[self.type]
        except KeyError:
            confp.error(self.tokens[0].lineno,
                        "`%s' is not argument type" % self.type)

    def __init__(self, type):
        self.type = type

    def _value_to_init(self):
        return self.type


class ValuesOptionAttribute(OptionAttribute):

    option_default_value = []
    var_type = [ConfigToken.STRING, ConfigToken.INT,
                ConfigToken.FLOAT]

    def __init__(self, *values):
        self.values = values

    def _value_to_init(self):
        return self.values


class DefaultOptionAttribute(ValuesOptionAttribute):

    name = 'default'
    option_attr = 'default_values'

    def validate_depend(self, confp, opt):
        for i, v in enumerate(self.values):
            if not corresponds_to(opt.arg_type, v):
                confp.error(self.tokens[i].lineno,
                            "type of `default' option attribute values "
                            "must be same as argument type")


class ConstantOptionAttribute(ValuesOptionAttribute):

    name = 'const'
    option_attr = 'consts'

    def validate_unit(self, confp, opt):
        name = True
        for t in self.tokens:
            if name and t.type != ConfigToken.STRING:
                confp.error(t.lineno, "constant name must be string")
            name = not name
        if name is False:
            confp.error(ts[-1].lineno, "constant value is needed")

    def validate_depend(self, confp, opt):
        name = True
        for i, v in enumerate(self.values):
            if not name and not corresponds_to(opt.arg_type, v):
                confp.error(self.tokens[i].lineno,
                            "type of `const' option attribute values "
                            "must be pairs string and same as argument type")
            name = not name

    def __init__(self, *values):
        self.values = values
        self.consts = {}
        key = None
        for v in values:
            if key:
                self.consts[key] = v
                key = None
            else:
                key = v

    def _value_to_init(self):
        return self.consts


class SelectOptionAttribute(ValuesOptionAttribute):

    name = 'select'
    option_attr = 'selects'

    def validate_depend(self, confp, opt):
        for i, v in enumerate(self.values):
            if not corresponds_to(opt.arg_type, v):
                confp.error(self.tokens[i].lineno,
                            "type of `select' option attribute values "
                            "must be same as argument type")


class OnceOptionAttribute(OptionAttribute):

    name = 'once'
    option_attr = 'once'
    option_default_value = False

    def _value_to_init(self):
        return True


class CodeBlock(object):

    def __init__(self, lineno, code):
        self.lineno = lineno
        self.code = code

    def __str__(self):
        return self.code

    def __repr__(self):
        return '<CodeBlock %d:"%s"' % (self.lineno, shorten(self.code), 10)


LG_DECLS = {
    ConfigToken.C_DECL_DT : CDeclaration(),
    ConfigToken.PROGRAM_DT : ProgramDeclaration(),
    ConfigToken.VERSION_DT : VersionDeclaration(),
    ConfigToken.USAGE_DT : UsageDeclaration()
}

def init_opt_attrs(cls):
    if cls.name:
        OPTION_ATTRS[cls.name] = cls
        setattr(Option, cls.option_attr, cls.option_default_value)
    for scls in cls.__subclasses__():
        init_opt_attrs(scls)

OPTION_ATTRS = {}
init_opt_attrs(OptionAttribute)


#
# option types
#

class Type(object):

    pass


class StringType(Type):

    name = 'str'


class IntType(Type):
    
    name = 'int'


class LongType(Type):
    
    name = 'long'


class FloatType(Type):
    
    name = 'float'


class DoubleType(Type):
    
    name = 'double'


class BoolType(Type):
    
    name = 'bool'


class BytesType(Type):
    
    name = 'bytes'


class DateType(Type):
    
    name = 'date'


class TimeType(Type):
    
    name = 'time'


class DateTimeType(Type):
    
    name = 'datetime'


type_dict = {}
for cls in Type.__subclasses__():
    type_dict[cls.name] = cls()


#
# utilities
#

def is_short_option(opt):
    return re.match('-\w\Z', opt)

def is_long_option(opt):
    return re.match('-?-\w+[\w-]*\Z', opt)

def is_sp_option(opt):
    return opt in ('-', 'pos')

def print_debug(msg):
    if options.debug:
        print "DEBUG: " + msg

def print_verbose(msg):
    if options.debug or options.verbose:
        print "# " + msg

def shorten(s, n, sign='...'):
    if len(s) > n:
        return s[0:n] + sign
    else:
        return s

def py_values(ts):
    return [t.py_value() for t in ts]

def corresponds_to(arg, value):
    if arg == STR_ARG_TYPE and isinstance(value, str):
        return True
    elif arg == INT_ARG_TYPE and isinstance(value, int):
        return True
    elif arg == UINT_ARG_TYPE and isinstance(value, int) and value >= 0:
        return True
    elif arg == FLOAT_ARG_TYPE and isinstance(value, float):
        return True
    else:
        return False

def cstring(s):
    return '"%s"' % re.subn('"', '\\"', s)[0]

def crepr(type, value):
    if type == STR_ARG_TYPE:
        return cstring(value)
    elif type in (INT_ARG_TYPE, UINT_ARG_TYPE, FLOAT_ARG_TYPE):
        return str(value)
    else:
        raise ValueError, 'unknown type -- %d' % t


if __name__ == '__main__':
    run(sys.argv)
